﻿using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Text;

namespace IOP.AspNetCore.Extension.Auth
{
    /// <summary>
    /// JWT注册认证服务类
    /// </summary>
    public static class JWTAuthenticationExtensions
    {
        /// <summary>
        /// 添加认证客户端服务
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IServiceCollection AddJWTAuthentication(this IServiceCollection services, IConfiguration Configuration)
        {
            var audienceConfig = Configuration.GetSection("JWTAuthentication") ?? throw new ArgumentNullException("Audience is Null in appsettings.json");
            var symmetricKeyAsBase64 = audienceConfig["Secret"] ?? throw new NullReferenceException("Secret is Null in appsettings.json");
            var issuer = audienceConfig["Issuer"] ?? throw new NullReferenceException("Issuer is Null in appsettings.json");
            var audience = audienceConfig["Audience"] ?? throw new NullReferenceException("Audience is Null in appsettings.json");
            var expiration = audienceConfig["Expiration"] ?? "5000";


            var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
            var signingKey = new SymmetricSecurityKey(keyByteArray);

            var tokenOption = new TokenOptions
            {
                Audience = audience,
                Issuer = issuer,
                SigningCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256),
                Expiration = TimeSpan.FromMinutes(double.Parse(expiration)),
            };

            services.AddSingleton<IOptions<TokenOptions>>(tokenOption);

            return CreateJWTService(services, tokenOption, signingKey);
        }

        /// <summary>
        /// 添加认证客户端服务
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IServiceCollection AddJWTAuthentication(this IServiceCollection services, Action<TokenOptions> options)
        {
            var tokenOption = new TokenOptions();
            options(tokenOption);
            services.AddSingleton<IOptions<TokenOptions>>(tokenOption);

            return CreateJWTService(services, tokenOption, tokenOption.SigningCredentials.Key as SymmetricSecurityKey);
        }

        private static IServiceCollection CreateJWTService(IServiceCollection services, TokenOptions options, SymmetricSecurityKey key)
        {
            var tokenValidationParameters = new TokenValidationParameters
            {
                //签名密钥必须匹配
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = key,

                // 验证JWT发行人是否有效
                ValidateIssuer = true,
                ValidIssuer = options.Issuer,

                // 验证JWT订阅者是否有效
                ValidateAudience = true,
                ValidAudience = options.Audience,

                // Validate the token expiry
                ValidateLifetime = true,

                ClockSkew = TimeSpan.Zero
            };
            //添加认证服务
            services.AddAuthentication(auth =>
            {
                auth.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                auth.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(o =>
            {
                //不使用https
                //o.RequireHttpsMetadata = false;
                o.TokenValidationParameters = tokenValidationParameters;
            });
            return services;
        }
    }
}
